/****************************************************************************************
 * 
 *  Author:         CFY
 *  Date:           2025-07-10
 *  Description:    消息队列模块
 *  Version:        V1.2
 * 
****************************************************************************************/

#include <errno.h>
#include "msg_queue.h"


/**
 * @brief   初始化消息队列
 * @param   name       要创建的消息队列名称
 * @return  成功返回     消息队列 id, 在 添加消息和
 *          失败返回    -1        
 */
int msg_queue_init(const char *name)
{
    char path[256];

    if(NULL == name)
    {
        printf("shmem_init(), name can not be empty!\n");
        return -1;
    }

    sprintf(path, "%s%s", MSG_QUEUE_PATH, name);

    // 检查文件是否存在
    if (0 != access(path, F_OK))        // 如果文件不存在才创建
    {
        char sys_cmd[256];
        sprintf(sys_cmd, "%s %s", "touch", path);   
        if(0 != system(sys_cmd))
        {
            ERROR("system");
            return -1;
        }
    }

    // 1. 创建 IPC 通信的 KEY
    key_t key = ftok(path, MSGQ_PROJ_ID);
    if(-1 == key)
    {
        ERROR("ftok");
        return -1;
    }

    // 2. 创建或打开消息队列
    int id = msgget(key, IPC_CREAT|0666);
    if(-1 == id)
    {
        ERROR("msgget");
        return -1;
    }
}

/**
 * @brief   向消息队列中添加消息
 * @param   msg         要发送的消息， 第一个字段是long类型的消息类型
 * @param   msgsz       消息正文的大小
 * @param   msgflg      标志位， 0 阻塞发送， IPC_NOWAIT 非阻塞发送
 * @return  成功返回    0
 *          失败返回    -1        
 */
int msg_queue_send(int id, const void *msg, size_t msgsz, int msgflg)
{
    
    // 向消息队列中添加消息
    if(-1 == msgsnd(id, msg, msgsz, msgflg))
    {
        ERROR("msgsnd");
        return -1;
    }

    return 0;
}


/**
 * @brief   从消息队列中读取消息
 * @param   msg         要接收的消息， 第一个字段是long类型的消息类型
 * @param   msgsz       msg消息正文的大小
 * @param   msgtyp      消息类型 0 读取第一条消息， >0 读取指定类型的第一条消息
 * @param   msgflg      标志位， 0 阻塞发送， IPC_NOWAIT 非阻塞发送
 * @return  成功返回    从消息队列读取到的正文字节数
 *          失败返回    -1        
 */
int msg_queue_recv(int id, void *msg, size_t msgsz, long msgtyp, int msgflg)
{

    // 从消息队列中读取
    int size = msgrcv(id, msg, msgsz, msgtyp, msgflg);
    if(-1 == size)
    {
        ERROR("msgrcv");
        return -1;
    }

    return size;
}


/**
 * @brief   删除消息队列
 * @param   id              消息队列的id
 * @return  成功返回    0
 *          失败返回    -1        
 */
int msg_queue_del(int id)
{
    //  删除消息队列
    if(-1 == msgctl(id, IPC_RMID, NULL))
    {
        ERROR("msgctl");
        return -1;
    }

    return 0;
}